﻿using System;
using System.Text;
using System.Web;
using System.Data.SqlClient;
using UDS.Components;
using System.Data;
using System.IO;

namespace UDS.Entity
{
    public class PFFileInfo
    {
        public int Id { get; set; }
        public int DirectoryId { get; set; }

        /// <summary>
        /// get the name of its parent directory
        /// </summary>
        public string DirectoryName { get; internal set; }
        public string Name { get; set; }
        public int Size { get; set; }
        public int Version { get; set; }
        public string VPath { get; set; }
        public DateTime TimeCreated { get; set; }
        public DateTime LastModified { get; set; }

        private const string PFRootFolder = @"~\Files\PersonalFiles\";

        public static int Create(int ownerId, int directoryId, HttpPostedFile attachment)
        {
            string fileName = HttpUtil.GetNameOfPostedFile(attachment);
            if (string.IsNullOrEmpty(fileName))
            {
                throw new ArgumentException("An empty attachment", "attachment");
            }
            string vPath = string.Format(PFRootFolder + @"{0}\{1}", ownerId, Guid.NewGuid().ToString("D"));
            var parameters = new SqlParameter[]
            {
                Database.MakeParam("@fileId", SqlDbType.Int, 4, ParameterDirection.InputOutput, 0),
                Database.MakeInParam("@directoryId", SqlDbType.Int, 4, directoryId),
                Database.MakeInParam("@name", SqlDbType.NVarChar, 256, fileName),
                Database.MakeInParam("@size", SqlDbType.Int, 4, attachment.ContentLength),
                Database.MakeInParam("@vPath", SqlDbType.NVarChar, 512, vPath),
            };

            using (var db = new Database())
            {
                using (db.BeginTransaction())
                {
                    if (directoryId <= 0)
                    {
                        // create the file to the root directory
                        directoryId = PFDirectoryInfo.GetRootDirectory(db, ownerId);
                        parameters[1].Value = directoryId;
                    }

                    // First create a new record in database
                    db.RunProc("dbo.sproc_File_CreateUpdateFile_V2", parameters);
                    int fileId = (int)parameters[0].Value;

                    if (fileId <= 0)
                    {
                        throw new InvalidOperationException("Failed to create a new file.");
                    }

                    // Get the physical path of the file.
                    string physicalPath = HttpUtil.MapPath(vPath);

                    // Ensure the directory exists
                    DirectoryInfo dirInfo = new DirectoryInfo(Path.GetDirectoryName(physicalPath));
                    if (!dirInfo.Exists)
                    {
                        dirInfo.Create();
                    }

                    // Save the file
                    attachment.SaveAs(physicalPath);

                    // Finally commit the transaction
                    db.Commit();

                    return fileId;
                }
            }
        }

        public static void Delete(int ownerId, int fileId)
        {
            var parameters = new SqlParameter[]
            {
                Database.MakeInParam("@ownerId", SqlDbType.Int, 4, ownerId),
                Database.MakeInParam("@fileId", SqlDbType.Int, 4, fileId),
            };

            using (var db = new Database())
            {
                using (db.BeginTransaction())
                {
                    // get the information about the given file
                    PFFileInfo f = GetFileInfo(db, ownerId, fileId);
                    if (f == null)
                    {
                        throw new InvalidOperationException("找不到指定的文件！");
                    }

                    // delete the record from the database first
                    db.RunProc("dbo.sproc_File_DeleteFile_V2", parameters);

                    // delete the physical file then
                    string physicalPath = HttpUtil.MapPath(f.VPath);
                    File.Delete(physicalPath);

                    // commit the transaction finally
                    db.Commit();
                }
            }
        }

        public static PFFileInfo GetFileInfo(int ownerId, int fileId)
        {
            var parameters = new SqlParameter[]
            {
                Database.MakeInParam("@ownerId", SqlDbType.Int, 4, ownerId),
                Database.MakeInParam("@fileId", SqlDbType.Int, 4, fileId),
            };

            using (var db = new Database())
            {
                using (var dr = db.RunDataReader("dbo.sproc_File_GetFile_V2", parameters))
                {
                    if (dr.Read())
                    {
                        PFFileInfo f = ReadFileInfo(dr);
                        f.DirectoryName = Convert.ToString(dr["DirectoryName"]);

                        return f;
                    }
                }
            }
            return null;
        }

        private static PFFileInfo GetFileInfo(Database db, int ownerId, int fileId)
        {
            var parameters = new SqlParameter[]
            {
                Database.MakeInParam("@ownerId", SqlDbType.Int, 4, ownerId),
                Database.MakeInParam("@fileId", SqlDbType.Int, 4, fileId),
            };

            using (var dr = db.RunDataReader("dbo.sproc_File_GetFile_V2", parameters))
            {
                if (dr.Read())
                {
                    PFFileInfo f = ReadFileInfo(dr);
                    f.DirectoryName = Convert.ToString(dr["DirectoryName"]);

                    return f;
                }
            }
            return null;
        }

        internal static PFFileInfo ReadFileInfo(IDataReader dr)
        {
            var f = new PFFileInfo();
            f.Id = (int)dr["FileId"];
            f.DirectoryId = (int)dr["DirectoryId"];
            f.Name = Convert.ToString(dr["Name"]);
            f.Version = (int)dr["Version"];
            f.Size = (int)dr["Size"];
            f.VPath = Convert.ToString(dr["VPath"]);
            f.TimeCreated = Convert.ToDateTime(dr["TimeCreated"]);
            f.LastModified = Convert.ToDateTime(dr["LastModified"]);
            return f;
        }
    }
}
